#include "pch.h"
#include "DDS_DLL.h"
#include "common.h"
#include "CParticipantCtrl.h"
#include "RWLock.h"
#ifdef _WIN32
#ifndef _WIN64
#pragma comment(lib,"lib/thirdparty/labview.lib")
#else
#pragma comment(lib,"lib/thirdparty_x64/labview.lib")
#endif
#endif

extern void logFile(const std::string& file_name, const std::string& msg);
static DDS_PARAMETER::DDS_Attribute s_dds_attr;
static std::unordered_map<std::string, std::shared_ptr<CParticipantCtrl>> s_ptcpname_dds;
static RWLock s_rwlock;
static std::string get_ptcpname_ddsptcp_key(unsigned int domain_id, std::string ptcpname) {
    return std::to_string(domain_id) + "/" + ptcpname;
}

void set_domain_id(unsigned int domain_id)
{
    s_dds_attr.domain_participant_attr.domain_id = domain_id;
}

void add_whitelist(const char* ip)
{
    s_dds_attr.net_attr.whiteLists.push_back(ip);
}

void clear_whitelist()
{
    s_dds_attr.net_attr.whiteLists.clear();
}

void set_tls(bool use_tls)
{
    s_dds_attr.net_attr.use_tls = use_tls;
}

void set_history_kind(unsigned short kind)
{
    s_dds_attr.data_writer_reader_attr.history_kind = (DDS_PARAMETER::HistoryKind)kind;
}

void set_history_depth(unsigned int depth)
{
    s_dds_attr.data_writer_reader_attr.depth = depth;
}

void set_max_samples(unsigned int max_samples)
{
    s_dds_attr.data_writer_reader_attr.max_samples = max_samples;
}

void set_extra_samples(unsigned int extra_samples)
{
    s_dds_attr.data_writer_reader_attr.extra_samples = extra_samples;
}

void set_allocated_samples(unsigned int allocated_samples)
{
    s_dds_attr.data_writer_reader_attr.allocated_samples = allocated_samples;
}

void set_publish_mode(unsigned short mode)
{
    s_dds_attr.data_writer_reader_attr.pub_mode = (DDS_PARAMETER::PublishMode)mode;
}

void set_reliability(unsigned short reliability)
{
    s_dds_attr.data_writer_reader_attr.reliability = (DDS_PARAMETER::Reliability)reliability;
}

void set_durability(unsigned short durability)
{
    s_dds_attr.data_writer_reader_attr.durability = (DDS_PARAMETER::Durability)durability;
}

void set_domain_participant_qos_name(const char* name)
{
    s_dds_attr.domain_participant_attr.domain_participant_qos_name = name;
}

void set_topic_name(const char* name)
{
    s_dds_attr.data_writer_reader_attr.topic_name = name;
}

void set_segment_size(unsigned int segment_size)
{
    s_dds_attr.shm_attr.segment_size = segment_size;
}

void set_max_message_size(unsigned int max_message_size)
{
    s_dds_attr.max_message_size = max_message_size;
}

void set_send_recv_buffer(unsigned int send_buffer, unsigned int recv_buffer)
{
    s_dds_attr.net_attr.send_buffer = send_buffer;
    s_dds_attr.net_attr.recv_buffer = recv_buffer;
}

void set_send_buffer(unsigned int send_buffer)
{
    s_dds_attr.net_attr.send_buffer = send_buffer;
}

void set_recv_buffer(unsigned int recv_buffer)
{
    s_dds_attr.net_attr.recv_buffer = recv_buffer;
}

void set_xml_profile(const char* profile_name, const char* xml_file_path)
{
    s_dds_attr.xml_profile.profilename_xmlpath[profile_name] = xml_file_path;
}

void set_reader_callback(LVUserEventRef ref)
{
    s_dds_attr.data_writer_reader_attr.call_back_ref = ref;
}

unsigned int init(unsigned short trans_type, unsigned short is_publisher)
{
    auto key = get_ptcpname_ddsptcp_key(s_dds_attr.domain_participant_attr.domain_id, s_dds_attr.domain_participant_attr.domain_participant_qos_name);
    std::shared_ptr<CParticipantCtrl> dds_;
    WLockGuard locker(s_rwlock);
    if (!s_ptcpname_dds.count(key)) {
        dds_ = std::shared_ptr<CParticipantCtrl>(new CParticipantCtrl);
    }
    else {
        dds_ = s_ptcpname_dds[key];
    }
    
    s_dds_attr.trans_type = (DDS_PARAMETER::TransportType)trans_type;
    auto ret = dds_->init(s_dds_attr, is_publisher);
    if (DDS_PARAMETER::e_ok == ret && !s_ptcpname_dds.count(key)) {
        s_ptcpname_dds[key] = dds_;
    }
    return ret;
}
unsigned int init_by_xml_profile(const char *xml_path, unsigned int domain_id, const char* participant_profile,
    /*const char* type_name,*/ const char* topic_profile,
    const char* rw_profile, const char* topic_name, unsigned short is_publisher)
{
    auto key = get_ptcpname_ddsptcp_key(domain_id, participant_profile);
    std::shared_ptr<CParticipantCtrl> dds_;
    WLockGuard locker(s_rwlock);
    if (s_ptcpname_dds.count(key)) {
        dds_ = s_ptcpname_dds[key];
    }
    else {
        dds_ = std::make_shared<CParticipantCtrl>();
    }
    auto ret = 
        dds_->init_by_xml_profile(s_dds_attr, xml_path, domain_id, participant_profile, 
            topic_profile, "Message", rw_profile, topic_name, is_publisher);
    if (DDS_PARAMETER::e_ok == ret) {
        s_ptcpname_dds[key] = dds_;
    }
    return ret;
}


unsigned int init_all_by_default_qos(unsigned int domain_id, const char* participant_name, 
    const char* topic_name, const char* type_name, unsigned short is_publisher)
{
    auto key = get_ptcpname_ddsptcp_key(domain_id, participant_name);
    std::shared_ptr<CParticipantCtrl> dds_;
    WLockGuard locker(s_rwlock);
    if (s_ptcpname_dds.count(key)) {
        dds_ = s_ptcpname_dds[key];
    }
    else {
        dds_ = std::make_shared<CParticipantCtrl>();
    }
    auto ret =
        dds_->init_all_by_default_qos(domain_id, type_name,participant_name, 
            topic_name, s_dds_attr.data_writer_reader_attr.call_back_ref, is_publisher);
    if (DDS_PARAMETER::e_ok == ret) {
        s_ptcpname_dds[key] = dds_;
    }
    return ret;
}

unsigned int publish(unsigned int domain_id, const char* participant_name, const char* topic_name, 
    unsigned int index, unsigned long long timestamp, const char *msg, unsigned int msg_len)
{
    auto key = get_ptcpname_ddsptcp_key(domain_id, participant_name);
    RLockGuard locker(s_rwlock);
    if (!s_ptcpname_dds.count(key)) {
        return DDS_PARAMETER::e_ptcp_not_init;
    }
    
    auto ret = s_ptcpname_dds[key]->publish(topic_name, index, timestamp, std::string(msg, msg_len));
    return ret;
}

void free_data(void* data)
{
    free(data);
}

int has_matched(unsigned int domain_id, const char* participant_name, const char* topic_name, unsigned short is_publisher)
{
    auto key = get_ptcpname_ddsptcp_key(domain_id, participant_name);
    RLockGuard locker(s_rwlock);
    return (s_ptcpname_dds.count(key) && s_ptcpname_dds[key] && s_ptcpname_dds[key]->has_matched(topic_name, is_publisher));
}

void remove_participant(unsigned int domain_id, const char* participant_name)
{
    auto key = get_ptcpname_ddsptcp_key(domain_id, participant_name);
    WLockGuard locker(s_rwlock);
    if(s_ptcpname_dds.count(key))
        s_ptcpname_dds.erase(key);
}

void remove_publisher(unsigned int domain_id, const char* participant_name, const char* topic_name)
{
    auto key = get_ptcpname_ddsptcp_key(domain_id, participant_name);
    RLockGuard locker(s_rwlock);
    if (s_ptcpname_dds.count(key))
        s_ptcpname_dds[key]->remove_publisher(topic_name);
}
void remove_subscriber(unsigned int domain_id, const char* participant_name, const char* topic_name)
{
    auto key = get_ptcpname_ddsptcp_key(domain_id, participant_name);
    RLockGuard locker(s_rwlock);
    if (s_ptcpname_dds.count(key))
        s_ptcpname_dds[key]->remove_subscriber(topic_name);
}

void remove_topic(unsigned int domain_id, const char* participant_name, const char* topic_name)
{
    auto key = get_ptcpname_ddsptcp_key(domain_id, participant_name);
    RLockGuard locker(s_rwlock);
    if (s_ptcpname_dds.count(key))
        s_ptcpname_dds[key]->remove_topic(topic_name);
}
